/**
 * @author WY
 * @since 2024/03
 */

import { THREEADDONS, THREE } from '@amcax/web-render';
import { useRenderStore } from '../store';

const { LineSegments2, LineGeometry, LineMaterial, LineSegmentsGeometry } =
  THREEADDONS;
const DEFAULT_LINE_COLOR = 0xf75ef7;
const RENDERORDER_EDGE = 2;
export type CSLineAttrs = {
  vertexes?: Array<THREE.Vector3Tuple>; // 顶点
  dashed?: boolean; // 虚线/*  */
  color?: string | number; // 颜色
  lineWidth?: number; // 线宽
  dashSize?: number; // 虚线长度
  gapSize?: number; // 虚线间隔
  renderOrder?: number; // z-index
  name?: string; // 类型区分
  depthTest?: boolean; // 是否开启深度测试
  maxPoints?: number; // 最大支持的顶点个数
  type?: 'segments' | undefined;
};

type FunctionOnBeforeRender = (renderer: THREE.WebGLRenderer) => void;
export class CSLine extends LineSegments2 {
  private readonly initDashSize: number;
  private readonly initGapSize: number;
  scene: THREE.Object3D;
  maxPoints: number = 110; // 最多支持的顶点个数;
  constructor(attrs?: CSLineAttrs) {
    super(
      attrs.type === 'segments'
        ? new LineSegmentsGeometry()
        : new LineGeometry(),
      new LineMaterial(),
    );
    this.initDashSize = attrs.dashSize || 15;
    this.initGapSize = attrs.gapSize || 5;
    this.name = attrs?.name ?? 'csline';
    this.userData = {};
    this.init(attrs);
    if (attrs?.dashed) {
      this.onBeforeRender = this.makeOnBeforeRender(this.onBeforeRender);
    }
  }
  private makeOnBeforeRender(
    parentOnBeforeRender: FunctionOnBeforeRender,
  ): FunctionOnBeforeRender {
    return (renderer: THREE.WebGLRenderer) => {
      // 调用父类的onBeforeRender，重新计算分辨率
      parentOnBeforeRender?.call(this, renderer);
      if (this.getDashed()) {
        const zoom = this.getZoom();
        this.setDashSize(this.initDashSize / zoom);
        this.setGapSize(this.initGapSize / zoom);
      }
    };
  }

  getZoom() {
    return (
      useRenderStore.getState().mainRenderer?.cameraManager?.camera?.zoom || 1
    );
  }

  getType() {
    return 'CSLine';
  }

  init(attrs?: CSLineAttrs) {
    if (attrs?.maxPoints) {
      this.maxPoints = attrs?.maxPoints;
      this.geometry.setPositions(new Float32Array(this.maxPoints * 3));
    }
    this.material = new LineMaterial({
      polygonOffset: true,
      polygonOffsetFactor: -10,
      polygonOffsetUnits: -10,
      depthTest: attrs?.depthTest ?? false,
      depthWrite: attrs?.depthTest ?? false,
      linewidth: attrs?.lineWidth ?? 2,
      color: attrs?.color ?? DEFAULT_LINE_COLOR,
      dashed: attrs?.dashed ?? false,
      dashSize: attrs?.dashSize ?? 15,
      gapSize: attrs?.gapSize ?? 5,
    });
    if (attrs) {
      if (attrs?.dashed !== undefined) this.setDashed(attrs.dashed);
      if (attrs?.gapSize != undefined) this.setGapSize(attrs.gapSize);
      if (attrs?.dashSize != undefined) this.setDashSize(attrs.dashSize);
      this.setRenderOrder(attrs.renderOrder);
      this.update(attrs);
    }
  }
  /**
   * 设置顶点
   * @param vertexs  [vector3 , vector3 ...]
   */
  setVertexs(vertexs: Array<THREE.Vector3Tuple>) {
    if (!vertexs && vertexs?.length <= 0) return this;
    this.userData.vertexs = vertexs;
    // 线段是成对的，数组中间的点都需要重复一次
    const positions = [];
    for (let i = 0; i < vertexs.length - 1; i++) {
      positions.push(vertexs[i][0], vertexs[i][1], vertexs[i][2]);
      positions.push(vertexs[i + 1][0], vertexs[i + 1][1], vertexs[i + 1][2]);
    }
    // 直接设置 this.geometry 有bug，所以这里重新new一个
    const newGeometry = new LineSegmentsGeometry();
    newGeometry.setPositions(positions);
    this.geometry.dispose();
    this.geometry = newGeometry;
    this.computeLineDistances();
    return this;
  }

  getVertexs() {
    return this.userData.vertexs as Array<THREE.Vector3Tuple>;
  }

  // 虚线材质
  setDashed(dashed: boolean) {
    this.material.dashed = dashed;
    this.userData.dashed = dashed;
    if (dashed) {
      this.material.defines.USE_DASH = '';
    } else {
      delete this.material.defines.USE_DASH;
    }
    this.material.needsUpdate = true;
    return this;
  }

  getDashed() {
    return this.material.dashed;
  }

  // 材质: 虚线长度
  setDashSize(size: number) {
    this.userData.dashSize = size;
    this.material.dashSize = size;
    return this;
  }
  // 材质: 虚线间隔
  setGapSize(size: number) {
    this.userData.gapSize = size;
    this.material.gapSize = size;
    return this;
  }

  // 线宽
  setLineWidth(linewidth = 2) {
    this.material.linewidth = linewidth;
    return this;
  }
  // 颜色
  setColor(color: string | number | Array<number>) {
    let c: string | number | THREE.Color;
    if (Array.isArray(color)) {
      c = new THREE.Color().fromArray(color);
    } else {
      c = color ?? DEFAULT_LINE_COLOR;
    }
    this.userData.color = c;
    this.material.color.set(c);
    return this;
  }

  // 设置透明度
  setOpacity(opacity = 0.5) {
    this.material.transparent = true;
    this.material.opacity = opacity;
    return this;
  }

  getColor() {
    return this.userData.color;
  }
  setRenderOrder(v = RENDERORDER_EDGE) {
    this.userData.renderOrder = v;
    this.renderOrder = v;
    return this;
  }

  setDepthTest(v = false) {
    this.userData.depthTest = v;
    this.material.depthTest = v;
    return this;
  }

  getDepthTest() {
    return this.userData.depthTest;
  }

  getRenderOrder() {
    return this.userData.renderOrder;
  }

  getLength() {
    const ver = this.getVertexs().map((v) => new THREE.Vector3(...v));
    const length = ver[0].clone().distanceTo(ver[1].clone());
    return length;
  }

  cloneSelf() {
    const attrs = this.getData();
    const result = new CSLine(this.getData());
    if (
      attrs.vertexs == null &&
      this.geometry instanceof LineSegmentsGeometry
    ) {
      const newGeometry = new LineSegmentsGeometry();
      // LineSegmentsGeometry特色的clone
      const newPositions = (this.geometry.getAttribute('instanceStart') as any)
        ?.data?.array;
      if (newPositions) {
        newGeometry.setPositions(newPositions);
      }
      result.geometry = newGeometry;
    }
    return result;
  }

  update(attrs?: CSLineAttrs) {
    // 保存用户配置
    attrs.color && this.setColor(attrs.color);
    attrs.dashSize && this.setDashSize(attrs.dashSize);
    attrs.gapSize && this.setGapSize(attrs.gapSize);
    attrs.lineWidth && this.setLineWidth(attrs.lineWidth);
    attrs.renderOrder && this.setRenderOrder(attrs.renderOrder);
    attrs.depthTest && this.setDepthTest(attrs.depthTest);
    if (attrs?.dashed != null) {
      this.setDashed(attrs.dashed);
    }
    if (attrs?.vertexes?.length > 0) {
      this.setVertexs(attrs.vertexes);
      this.computeLineDistances();
    }
    return this;
  }
  // 销毁当前对象
  destroy() {
    this.scene?.remove(this);
    this.geometry.dispose();
    this.material.dispose();
  }
  /**
   * @description 添加到场景中去
   * @param { Object3D } scene
   **/
  addTo(scene: THREE.Object3D) {
    this.scene = scene;
    this.scene.add(this);
  }

  getData() {
    const json: { [k: string]: any } = { ...this.userData };
    return json;
  }
}
